//============================================================================
// Name        : NmpsStreamer.cpp
// Author      : Shaohong
// Version     :
// Description : Comnet2011 NMPS class assignment.
//============================================================================

#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <ctype.h>
#include "AppLogger.h"
#include "GlobalVariables.h"
#include "HttpHelper.h"
#include "ParsingUtils.h"
#include "usageHelper.h"
#include "SipServer.h"
#include "RadioChannel.h"
#include "RadioStreamer.h"
#include "NmpsException.h"
#include "RadioStation.h"

#include <iostream>

using namespace std;
using namespace nmps;

static AppLogger * logger = AppLogger::getInstance("Main");

/*
 *The SIG_INT handler for the main process.
 */
void mainSigIntHandler(int sigNo) {
	RadioStation::instance()->stopAllActiveStations();
	RadioStation::instance()->dumpRadioStreamerHistory(cerr);
	exit(EXIT_FAILURE);
}


/*
 * helper function to install signal handler for the given signal
 */
void setupSigHandler(int sigNo, void(*sigHandler)(int)) {
	struct sigaction sigIntAction;

	//we won't block any during our execution
	sigemptyset(&sigIntAction.sa_mask);

	//no special options
	sigIntAction.sa_flags = 0;

	//set the SIGINT handler
	sigIntAction.sa_handler = sigHandler;

	assert((sigaction(sigNo, &sigIntAction, NULL)) == 0);
}

static void printChannelList(list<RadioChannel> & channelList) {

	cerr << "Channel list:" << endl;
	if (channelList.empty()) {
		return;
	}

	list<RadioChannel>::iterator itr = channelList.begin();
	while (itr != channelList.end()) {
		cout << itr->channelNumber << ". " << itr->title
				<< "[" << itr->channelID << "]" << endl;
		itr++;

	}

}

static RadioChannel getSelectedChannel(list<RadioChannel> & channelList, int channelNumber) {
    list<RadioChannel>::iterator itr = channelList.begin();
    while(itr != channelList.end()){
        if (itr->channelNumber == channelNumber) {
            return (* itr);
        }
        itr ++;
    }

    throw NmpsException("bad Channel Number");
}

int main(int argc, char ** argv) {


	// sets up the SIGINT handler for the main process
	setupSigHandler(SIGINT, mainSigIntHandler);

	parseCommandLine(argc, argv, &globalConfig);

	logger->debug("global configuration:");
	displayStreamerConfig(globalConfig);

	fprintf(stderr, "program is running in mode %d\n", globalConfig.programMode);

	logger->debug("retrieving remote HTML page");

	/**
	 * retrieve home page: according to the given HTTP URL
	 */
	HttpRequest httpRequest;
	string remoteURL = string(globalConfig.radioStationURL);
	httpRequest.remoteHostName = HttpHelper::extractHost(remoteURL);
	httpRequest.URI = HttpHelper::extractPath(remoteURL);
	httpRequest.remoteHostPort = HttpHelper::extractPort(remoteURL);

	HttpResponse response;
	HttpHelper::retrieveURIContent(httpRequest, response);

	logger->debug("Radio Station HomePage is \n%s", response.data);

	/**
	 * Parse the html page to extract play lists URIs
	 */
	list<RadioChannel> radioChannelList;
	ParsingUtils::extractPlayListURI(response.data, radioChannelList);

	printChannelList(radioChannelList);

	if (radioChannelList.empty()) {
		fprintf(stderr, "Channel List is empty :(\n");
		return EXIT_FAILURE;
	}

	if (globalConfig.programMode == assignment1Mode) {
		// Assignment #1 mode
		RadioStreamer * radioStreamer ;
		//create the default RadioStreamer
		list< pair<string, int>  > recipientList;
		ParsingUtils::parseRecipientList(globalConfig.recipientList, recipientList);


        // prompt user for channel selection
        unsigned int userSelectedChannelNumber;

        cout << "Please select the channel from the list above:";
        cin >> userSelectedChannelNumber;

        if (userSelectedChannelNumber != 0) {
            RadioChannel selectedChannel = getSelectedChannel(radioChannelList,
                    userSelectedChannelNumber);
            radioStreamer = new RadioStreamer(selectedChannel);

            // add recipient list
            radioStreamer->addRecipients(recipientList);

			printf("Currently playing Channel NO #%d \"%s\"\n", userSelectedChannelNumber, selectedChannel.title.c_str());
            radioStreamer->startStreaming();

            printf("Press [N]ext, [P]ause, [T]erminate:");
            while (true) {
                char userControl;
                cin >> userControl;
                if (toupper(userControl) == 'N') {
                	if (userSelectedChannelNumber == radioChannelList.size()) {
                		//wrap around to first channel
                		userSelectedChannelNumber = 1;
                	} else {
                		userSelectedChannelNumber ++;
                	}

                    //find the new channel
					selectedChannel = getSelectedChannel(radioChannelList, userSelectedChannelNumber);

					radioStreamer->switchChannel(selectedChannel);
					printf("Currently playing Channel NO #%d \"%s\"\n", userSelectedChannelNumber, selectedChannel.title.c_str());
                    printf("Press [N]ext, [P]ause, [T]erminate:");

                } else if (toupper(userControl) == 'P') {
                    radioStreamer->pauseStreaming();
                    printf("Press [N]ext, [C]ontinue, [T]erminate:");

                } else if (toupper(userControl) == 'C') {
                    radioStreamer->resumeStreaming();
                    printf("Press [N]ext, [P]ause, [T]erminate:");
                }

                else if (toupper(userControl) == 'T') {
                    radioStreamer->stopStreaming();
                    break;
                }

            }
        }

	}

	if (isSipServerEnable(globalConfig)) {
		// Assignment #2 mode
		SipServer sipServer;

		// give these radio channel information to the SipServer
		list<RadioChannel>::iterator itr = radioChannelList.begin();
		while (itr != radioChannelList.end()) {
			RadioStreamer * radioStreamer = new RadioStreamer(*itr);
			sipServer.addRadioStreamer(radioStreamer);
			itr++;
		}

		sipServer.startService();

		pthread_join(sipServer.getSipServerThread(), NULL);

	}

	RadioStation::instance()->dumpRadioStreamerHistory(std::cerr);

	return EXIT_SUCCESS;
}

